package com.bomberman.environment;

import com.bomberman.items.*;
import java.awt.Color;
import java.util.*;

import info.gridworld.actor.*;
import info.gridworld.grid.*;

public class BombWorld extends ActorWorld
// a modified ActorWorld to house the game
//This class facilitates interactions between the occupants (Actors),
//  controls timing with step(), and constructs mazes.
//*NOTE: almost every class in this project contains a BombWorld class variable
{
	private static ArrayList<Man> Players = new ArrayList<Man>();
	//2-Player, as it is. Expansion to multiple players would be easy
	Man P1;
	Man P2;
	//P1: A=left  S=down D=right W=up F=bomb
	//P2: J, K, L, I, H
	
	private static int c=0;
	private static int PupTimer;
	
	public ArrayList<Bomb> Bombs = new ArrayList<Bomb>();
	//Keeps track of bombs, explosions
	
	public ArrayList<Location> teleLocs;
	public ArrayList<Location> itemLocs;//unused
	
	public BombWorld()
	{
		P1 = new Man("ASDWF", Color.red, this);
		P2 = new Man("JKLIH", Color.blue, this);
		
		Players.add(P1);
		Players.add(P2);
		
		mazeSelect();
		show();
		
		setMessage("\tRED:"+P2.deaths+"\t\tBLUE:"+P1.deaths);
		step();
	}

	public boolean keyPressed(String description, Location unused)
	//Pressing a button either causes movement or lays a bomb, for a player
	{
		String desc = 
			description.substring(description.length()-1,description.length())
			.toUpperCase();
		int Pnum=-1;
		
		for(int i=0; i<Players.size(); i++)
		//finds the player who takes an action, then proceeds
		{
			if(Players.get(i).asdwf(desc)!=null)
				Pnum=i;
		}
		if(Pnum<0)
			return false;
		
		Man P = Players.get(Pnum);
		
		if(P.isDead())
			return false;
		
		desc = P.asdwf(desc);
		
		if(desc.equals("F"))
			{P.layBomb(); return true;}
		
		P.moveTo(desc);
			
		return true;
	}
	
	
	public void step()
	//the game's internal timer. Controls bomb explosions, item/player spawns
	{
		c++;
		super.step();
		
		ArrayList<Integer> toRemove = new ArrayList<Integer>();
		
		for(int i=0; i<Bombs.size(); i++)
		{
		Bomb bomb = Bombs.get(i);
			if(bomb.getFuse()==0)
				toRemove.add(i);
		}
		
		for(int i=0; i<toRemove.size(); i++)
		{Bombs.remove(toRemove.get(i));}
		
		Location itemLoc;
		if(itemLocs == null)
			itemLoc = randLoc();
		else
			itemLoc = itemLocs.get((int) (Math.random()*itemLocs.size()));
		
		if(getGrid().get(itemLoc)!=null)
			return;
				
		if(c%7==0)
			if(Math.random()<.2)
				if(Math.random()<.6)
					add(itemLoc,new PwrMax(this));
				else
					add(itemLoc,new InvulnUp(this));
			else
			if(Math.random()<.5)
				add(itemLoc,new PwrUp(this));
			else
				add(itemLoc,new BmbUp(this));
		

		setMessage("\tRED:"+P2.deaths+"\t\tBLUE:"+P1.deaths);
	}
	
	public void mazeSelect()
	//selects a maze
	{
		Scanner in = new Scanner(System.in);
		p("Input Maze #");
		int n = in.nextInt();
		
		switch (n)
		{
		case 6: {mazeRows(); break;}
		case 5: {mazeTight(); break;}
		case 4: {mazeWall(); break;}
		case 3: {mazeFort(); break;}
		case 2: {MazeRand mazeR = new MazeRand(this); break;}
		case 1: {MazeGrid mazeG = new MazeGrid(this); break;}
		default: {mazeBlank(); break;}
		}
	}
	
//	0	Blank (default) 8x8
	public void mazeBlank()
	{
		Location loc;
		add(randLoc(),P1);
		add(randLoc(),P2);
		
		teleLocs = new ArrayList<Location>();
		loc = randLoc();
		add(loc,new Tele(this, teleLocs, "cycleTele", loc));
		loc = randLoc();
		add(loc,new Tele(this, teleLocs, "cycleTele", loc));
		loc = randLoc();
		add(loc,new Tele(this, teleLocs, "cycleTele", loc));
		loc = randLoc();
		add(loc,new Tele(this, teleLocs, "cycleTele", loc));

		loc = randLoc();
		add(loc, new Shelter(this, loc));
	}
/*
8 8
--------
--------
--------
--------
--------
--------
--------
--------
 */

//	1	Standard Grid	9x9
	public void mazeGrid()
	{
		super.setGrid(new BoundedGrid<Actor>(9,9));
		
		for(int i=0; i<getGrid().getNumRows(); i++)
		for(int j=0; j<getGrid().getNumCols(); j++)
		{
			if(i%2==1 && j%2==1)
			add(new Location(i,j), new Rock(Color.LIGHT_GRAY));
		}
		
		add(new Location(0,0),P1);
		add(new Location(8,8),P2);
	}
/*
9 9
---------
-*-*-*-*-
---------
-*-*-*-*-
---------
-*-*-*-*-
---------
-*-*-*-*-
---------
 */

//	2	Random Maze		10x10
	public void mazeRand()
	{
		super.setGrid(new BoundedGrid<Actor>(10,10));
		int k = getGrid().getNumCols()*getGrid().getNumRows();
		
		for(int i=0; i<k/4; i++)
		{
			add(randLoc(), new Rock(Color.GRAY));
		}

		teleLocs = new ArrayList<Location>();
		Location loc = randLoc();
		add(loc,new Tele(this, teleLocs, "randTele", loc));
		loc = randLoc();
		add(loc,new Tele(this, teleLocs, "randTele", loc));
		
		add(randLoc(), P1);
		add(randLoc(), P2);
	}

//	3	2-Fort			12x12		
	public void mazeFort()
	{
		//DOES NOT WORK.
		
		ASCIImaze(
		"12 12\n"+
		"---T*II*T---\n"+
		"----*II*----\n"+
		"----*II*----\n"+
		"--***--***--\n"+
		"------------\n"+
		"-*--*--*--*-\n"+
		"-*--*--*--*-\n"+
		"------------\n"+
		"----*--*----\n"+
		"----*II*----\n"+
		"----*II*----\n"+
		"---T*II*T---"
		);
		
		/*
		super.setGrid(new BoundedGrid<Actor>(12,12));
		
		int x = getGrid().getNumRows();
		int y = getGrid().getNumCols();
		
		for(int i=0; i<x; i++)
		for(int j=0; j<y; j++)
		{
		if(
			((j==4||j==7) && (i<4||i>7||i==5||i==6))
			||
			((j==2||j==3||j==8||j==9) && (i==3||i==8))
			||
			((j==1||j==10) && (i==5||i==6))
		  )
				add(new Location(i,j), new Rock(Color.DARK_GRAY));
		}
		*/
		
		add(new Location(5,0),P1);
		add(new Location(6,11),P2);
	}
/*
12 12
----*II*----
--T-*II*-T--
----*II*----
--***--***--
------------
-*--*--*--*-
-*--*--*--*-
------------
--***--***--
----*II*----
--T-*II*-T--
----*II*----
 */
	
//	4	two separate areas, separated by a wall
	public void mazeWall()
	{
		ASCIImaze(
		"5 11\n" +
		"I---I*I---I\n" +
		"-----*-----\n" +
		"--T--*--T--\n" +
		"-----*-----\n" +
		"I---I*I---I");
		
		add(new Location(2,0), P1);
		add(new Location(2,10),P2);
	}

//	5	a tight loop
	public void mazeTight()
	{
		ASCIImaze(
		"6 6\n" +
		"II--II\n" +
		"I****I\n" +
		"-****-\n" +
		"-****-\n" +
		"I****I\n" +
		"II--II"	);
		
		add(new Location(0,0), P1);
		add(new Location(5,5), P2);
	}
	
//	6	three narrow rows, tele/items/tele
	public void mazeRows()
	{
		ASCIImaze(
		"5 9\n" +
		"----T----\n" +
		"-*******-\n" +
		"--IIIII--\n" +
		"-*******-\n" +
		"----T----"
		);
		
		add(new Location(2,0), P1);
		add(new Location(2,8), P2);
	}
	
	
	public void ASCIImaze(String ASCII)
	//NOT WORKING
	//converts a string into a maze.
	{
		ArrayList<Location> rockLocs = new ArrayList<Location>();
		ArrayList<Location> teleLocs = new ArrayList<Location>();
		ArrayList<Location> itemLocs = new ArrayList<Location>();
		
		Scanner in = new Scanner(ASCII);
		int Xdim = in.nextInt();
		int Ydim = in.nextInt();
		in.nextLine();
		
		for(int i=0; i<Xdim; i++)
		{
			String line = in.nextLine();
			for(int j=0; j<Ydim; j++)
			{
				if(line.charAt(j)=='*')
					rockLocs.add(new Location(i,j));
				if(line.charAt(j)=='T')
					teleLocs.add(new Location(i,j));
				if(line.charAt(j)=='I')
					itemLocs.add(new Location(i,j));
			}
		}
		super.setGrid(new BoundedGrid<Actor>(Xdim,Ydim));

		if(teleLocs.size()>1)
			this.teleLocs = new ArrayList<Location>();
		if(itemLocs.size()>1)
			this.itemLocs = itemLocs;
		
		for(Location loc : rockLocs)
			add(loc, new Rock());
		for(Location loc : teleLocs)
			add(loc, new Tele(this, this.teleLocs, "cycleTele", loc));
	}
	
	public Location randLoc()
	//random empty Location
	{
		int x;
		int y;
		do
		{
		x = (int) Math.floor(Math.random()*getGrid().getNumRows());
		y = (int) Math.floor(Math.random()*getGrid().getNumCols());
		}
		while (getGrid().get(new Location(x,y))!=null);
		
		return new Location(x,y);
	}
	
	public Location locMod(Location Loc, int x, int y)
	{
		return new Location(Loc.getRow()+x, Loc.getCol()+y);
	}
	
	public Location asdwLoc(String asdw, Location Loc)
	//converts ordinal direction + Location -> new Location (& validity check)
   {
		int x=Loc.getRow(); int y=Loc.getCol();
		
	   		if(asdw.equals("A") && Loc.getCol()>0) 		
	   			y--;
	   else if(asdw.equals("S") && Loc.getRow()<getGrid().getNumRows()) 	
		   		x++;
	   else if(asdw.equals("D") && Loc.getCol()<getGrid().getNumCols()) 	
		   		y++;
	   else if(asdw.equals("W") && Loc.getRow()>0) 		
		   		x--;
	   		
	   		
	   return new Location(x,y);
   }
	public static void p(String asdf)
	{System.out.println(asdf);}
}